package main

import (
	"fmt"
	"gocv.io/x/gocv"
	"image"
	"math"
	"sync"
	"time"
)

type TrackingCount struct {
	C_MinShift int
	AreaLimit  int
}

func NewTrackingCount(minShift int, areaLimit int) TrackingCount {
	tc := TrackingCount{}
	tc.C_MinShift = minShift
	tc.AreaLimit = areaLimit
	return tc
}

var (
	track = NewTrackingCount(1, 1) // 暂时为下面跟踪实现提供临时实现
)

func (the *TrackingCount) SignalCtrl(img gocv.Mat, rois []ROI, cameraZone int8) {
	//去除与边界相交的ROI
	for i := len(rois) - 1; i >= 0; i-- {
		if rois[i].W*rois[i].H < the.AreaLimit || rois[i].Y+rois[i].H >= img.Rows() || rois[i].X < 0 || rois[i].Y < 0 {
			rois = append(rois[:i], rois[i+1:]...)
		}
	}

	//在原始图像中画出检测框（包含方面
	//todo

	//region 从img中根据rois提取所有船舶信息ships
	channels := []int{0, 1}
	sizes := []int{25, 30}
	ranges := []float64{0, 180, 0, 255}
	var mask, hist gocv.Mat
	var ships []Ship
	for _, roi := range rois {
		ship := NewShip(roi)
		//计算并规范化直方图
		mask = img.Region(image.Rectangle{
			Min: image.Point{X: roi.X, Y: roi.Y},
			Max: image.Point{X: roi.X + roi.W, Y: roi.Y + roi.H},
		})
		gocv.CalcHist([]gocv.Mat{img}, channels, mask, &hist, sizes, ranges, true)
		gocv.Normalize(hist, &hist, 0, 1, gocv.NormMinMax)
		ship.Hist = hist
		ship.Area = ship.Roi.Area()
		ship.MaxArea = ship.Area
		ship.Y0 = ship.Roi.X + ship.Roi.W/2
		ship.cameraZone = cameraZone
		img.CopyTo(&ship.MaxImg)
		ships = append(ships, ship)
	}

	//用ships更新上游船舶信息_shipUps或下游船舶信息_shipDowns
	if cameraZone == 1 {
		ShipsUpdate(img, &ShipDowns, ships, cameraZone) //  下游区
	} else {
		ShipsUpdate(img, &ShipUps, ships, cameraZone) // 上游区
	}
}

func ShipsUpdate(img gocv.Mat, shipsLast *sync.Map, ships []Ship, cameraZone int8) {
	shipsLast.Range(func(key, value any) bool {
		var matchers []Matcher
		for k := range ships {
			matcher := Matcher{
				ind:       k,
				intersect: value.(*Ship).Roi.IsEqual(ships[k].Roi),
				dy:        ships[k].Roi.Y - value.(*Ship).Roi.Y,
				correl:    gocv.CompareHist(value.(*Ship).Hist, ships[k].Hist, gocv.HistCmpCorrel),
				bDist:     gocv.CompareHist(value.(*Ship).Hist, ships[k].Hist, gocv.HistCmpBhattacharya),
			}
			matchers = append(matchers, matcher)
		}
		//==找出边框相交的匹配Ship，取相交且距离最近的做为匹配对象
		nearIndDist, minDy := -1, 9000
		for k, v := range matchers {
			if v.intersect && int(math.Abs(float64(v.dy))) < minDy {
				nearIndDist = k
				minDy = int(math.Abs(float64(v.dy)))
			}
		}
		if nearIndDist >= 0 {
			ind := nearIndDist
			//更新shipsLast[i]：
			if int(math.Abs(float64(matchers[ind].dy))) > track.C_MinShift {
				ShipUpdate(img, value.(*Ship), &ships[ind], cameraZone)
			}
			ships = append(ships[:ind], ships[ind+1:]...)
			return true
		}
		nearIndBDist, nearIndCorrel, minBDist, maxCorrel := -1, -1, 1, 0
		for k, v := range matchers {
			if v.bDist < float32(minBDist) {
				nearIndDist = k
				minBDist = int(v.bDist)
			}
			if v.correl > float32(maxCorrel) {
				nearIndCorrel = k
				maxCorrel = int(v.correl)
			}
		}

		if nearIndBDist == nearIndCorrel && nearIndBDist >= 0 && nearIndCorrel >= 0 {
			//更新shipsLast[i]：
			ind := nearIndBDist
			if int(math.Abs(float64(matchers[ind].dy))) > track.C_MinShift {
				ShipUpdate(img, value.(*Ship), &ships[ind], cameraZone)
			}
			//移出已匹配的船舶
			ships = append(ships[:ind], ships[ind+1:]...)
			return true
		}
		//==找出巴氏距离小于0.4 且 相关性大于0.6
		var nearIndBDists, nearIndCorrels []int
		for k, v := range matchers {
			if v.bDist <= 0.4 {
				nearIndBDists = append(nearIndBDists, k)
			}
			if v.correl >= 0.6 {
				nearIndCorrels = append(nearIndCorrels, k)
			}
		}

		if len(nearIndBDists) > 0 && len(nearIndCorrels) > 0 {
			for k, v := range nearIndBDists {
				for _, v1 := range nearIndCorrels {
					if v == v1 {
						ind := nearIndBDists[k]
						//更新shipsLast[ind]：
						if int(math.Abs(float64(matchers[ind].dy))) > track.C_MinShift {
							ShipUpdate(img, value.(*Ship), &ships[ind], cameraZone)
						}
						//移出已匹配的船舶
						ships = append(ships[:ind], ships[ind+1:]...)
						goto loop
					}
				}
			}
		} else if len(nearIndBDists) > 0 {
			nearIndBDist = -1
			minBDist = 1
			for k, v := range nearIndBDists {
				if v < minBDist {
					nearIndBDist = k
					minBDist = v
				}
			}

			if nearIndBDist >= 0 {
				ind := nearIndBDist
				//更新shipsLast[ind]：
				if int(math.Abs(float64(matchers[ind].dy))) > track.C_MinShift {
					ShipUpdate(img, value.(*Ship), &ships[ind], cameraZone)
				}
				//移出已匹配的船舶
				ships = append(ships[:ind], ships[ind+1:]...)
				return true
			}
		} else if len(nearIndCorrels) > 0 { //==找出相关性大于0.6
			nearIndCorrel = -1
			maxCorrel = 0
			for k, v := range nearIndCorrels {
				nearIndCorrel = k
				maxCorrel = v

			}
			if nearIndCorrel >= 0 {
				ind := nearIndCorrel
				//更新shipsLast[ind]：
				if int(math.Abs(float64(matchers[ind].dy))) > track.C_MinShift {
					ShipUpdate(img, value.(*Ship), &ships[ind], cameraZone)
				}
				//移出已匹配的船舶
				ships = append(ships[:ind], ships[ind+1:]...)
				return true
			}
		}

		//==未找到匹配
		value.(*Ship).NoMatch++
		//连续3次未找到匹配
		if value.(*Ship).NoMatch >= 3 {
			//如果下游摄像头 且 向上游行驶
			if cameraZone > 0 && value.(*Ship).Direction < 0 {
				//单行通道上行总数+1
				countUp := ShipCount{
					startTime: time.Now().Unix(),
					waitMins:  time.Now().Unix() - value.(*Ship).waitMins,
					photo:     value.(*Ship).MaxImg,
				}
				CountUp.Store(countUp.startTime, countUp)
				if StateDown == 0 || StateDown == 2 {
					//...记录：违规信息（时间、下游、信号灯状态，照片）
					fmt.Println("违规操作")
				}
			} else if cameraZone > 0 && value.(*Ship).Direction > 0 {
				//单行通道下行总数+1
				countDown := ShipCount{
					startTime: time.Now().Unix(),
					waitMins:  time.Now().Unix() - value.(*Ship).waitMins,
					photo:     value.(*Ship).MaxImg,
				}
				CountDown.Store(countDown.startTime, countDown)
				if StateDown == 0 || StateDown == 2 {
					//...记录：违规信息（时间、下游、信号灯状态，照片）
					fmt.Println("违规操作")
				}
			}
			shipsLast.Delete(value.(*Ship).MaxDT)
		}
	loop:
		fmt.Println("退出循环")

		return true
	})

	for k := range ships {
		shipsLast.Store(ships[k].MaxDT, ships[k])
	}

}

func ShipUpdate(img gocv.Mat, shipSrc, ship *Ship, cameraZone int8) {
	shipSrc.State = 1
	shipSrc.Roi = ship.Roi
	ship.Hist.CopyTo(&shipSrc.Hist)
	shipSrc.Area = ship.Area
	shipSrc.Count++
	if shipSrc.Count%2 == 0 {
		dy := ship.Roi.Y + ship.Roi.H/2 - shipSrc.Y0
		if dy > 0 {
			shipSrc.Direction = 1
		} else {
			shipSrc.Direction = -1
		}
		shipSrc.Count = 0
		shipSrc.Y0 = ship.Roi.Y + ship.Roi.H/2
	}

}
